package com.chipcoo.domain.basal;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chipcoo.ResponseResult;
import com.chipcoo.models.gen.Finger;
import com.chipcoo.models.gen.Passport;
import com.chipcoo.services.ConfService;
import com.chipcoo.services.MessageService;
import com.chipcoo.services.UserService;
import com.chipcoo.services.WeiXinService;
import com.chipcoo.shiro.authc.FormAuthenticationFilter;
import com.chipcoo.utils.StringUtils;
import com.chipcoo.utils.ValidateUtils;
import com.chipcoo.web.utils.WebUtils;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.ContextLoader;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.Date;

import static com.chipcoo.web.utils.WebUtils.accessControl;

@Controller
@RequestMapping("passport")
public class PassportController {

    @Autowired
    private ConfService confService;
    @Autowired
    private UserService userService;

    @Autowired
    private MessageService messageService;

    @Autowired
    private WeiXinService weiXinService;



    private int beforeFingerPrint(HttpServletRequest req, HttpServletResponse res){
        if( WebUtils.ACCESS_CONTROL_ALLOW_ORIGINS ) {
            accessControl(req,res);
        }
        Session session = com.chipcoo.utils.SecurityUtils.getSession(false);
        if(null!=session) return ResponseResult.ERR_EXISTS;

        return 0;
    }
    @RequestMapping(value = "fingerprint",method = RequestMethod.GET)
    public ResponseResult fingerPrint(HttpServletRequest req, HttpServletResponse res){
        int errCode = beforeFingerPrint(req,res);
        if(errCode==0){
            //region 告之客户端提交设备信息
            WebUtils.setCookie(res,"cookie_enable","1",-1);
            //endregion
        }

        String returnUrl =WebUtils.getString(req,"returnUrl");
        if(StringUtils.isEmpty(returnUrl)) returnUrl = WebUtils.getURLReferer(req);
        if(StringUtils.isEmpty(returnUrl)) returnUrl = "/";

        return ResponseResult.createError(errCode).redirect(returnUrl);
    }
    @RequestMapping(value = "fingerprint",method = RequestMethod.POST)
    public ResponseResult fingerPrint(HttpServletRequest req, HttpServletResponse res
            , @CookieValue(value = "cookie_enable",required = false) String cookie_enable
            , @CookieValue(value = "finger_id",required = false) String originalFingerID){
        int errCode = beforeFingerPrint(req,res);
        String  szErr=null;
        if(errCode==0){
            if(null==cookie_enable ) {
                    errCode=ResponseResult.NOT_SUPPORT_COOKIE; //cookie not supports
            }else {
                WebUtils.removeCookie(res,"cookie_enable");

                //region 提交设备信息
                String id = WebUtils.getString(req,"finger");
                String jsonSchema = WebUtils.getString(req,"jsonSchema");

                if(StringUtils.isEmpty(id)) szErr = "id不能为空！";
                else if(StringUtils.isEmpty(jsonSchema)) szErr="jsonSchema不能为空！";
                else {
                    JSONObject jsonObject = null;
                    try {jsonObject = JSON.parseObject(jsonSchema);}catch (Exception ex){ ex.printStackTrace(); }
                    if(null==jsonObject) szErr="jsonSchema无效！";
                    else {
                        Finger finger = com.chipcoo.utils.SecurityUtils.parseDeviceFinger(jsonObject.getString("ua"), id, jsonObject);
                        if(null==finger) szErr= "参数错误！";
                        else createUpdateFinger(res,finger,originalFingerID);
                    }
                }
            }
        }
        String returnUrl =WebUtils.getString(req,"returnUrl");
        if(StringUtils.isEmpty(returnUrl)) returnUrl = "/";

        ResponseResult ret = null;
        if(null!=szErr) ret = new ResponseResult(szErr).setCode(ResponseResult.MSG_CUSTOM).redirect(returnUrl);
        else  ret = ResponseResult.createError(errCode).redirect(returnUrl);
        return ret;
    }
    private void  createUpdateFinger(HttpServletResponse res,Finger finger,String originalFingerID){
        Finger dbFinger=null;
        if(!StringUtils.isEmpty(originalFingerID)) {
            dbFinger = confService.getDeviceFinger(originalFingerID);
        }
        if (!finger.getId().equals(originalFingerID)) {
            //在客户端存储最新的finger_id;
            WebUtils.setCookie(res, "finger_id", finger.getId(), Integer.MAX_VALUE);
        }
        if(null==dbFinger) createUpdateCurrentFinger(finger);
        else {
            if(!dbFinger.getId().equals(finger.getId())){
                //设备有升级,delete then added new
                //delete orininal
                confService.deleteDeviceFinger(originalFingerID);
                //insert new
                finger.setCreatedAt(dbFinger.getCreatedAt());
                finger.setLastAccessed(new Date());
                finger.setUpdatedAt(finger.getLastAccessed());
                confService.insertDeviceFinger(finger);
            }
        }
        com.chipcoo.utils.SecurityUtils.setCurrentFinger(finger);
    }

    /**
     * 插入或更新新finger
     * @param finger
     */
    private void createUpdateCurrentFinger(Finger finger){
        //created new
        if(  null==confService.getDeviceFinger(finger.getId()) ) {
            finger.setCreatedAt(new Date());
            finger.setLastAccessed(finger.getCreatedAt());
            finger.setUpdatedAt(finger.getLastAccessed());

            confService.insertDeviceFinger(finger);
        }else {
            //update
            Finger fingerUpdate = new Finger();
            fingerUpdate.setId(finger.getId());

            fingerUpdate.setLastAccessed(new Date());
            confService.updateDeviceFinger(fingerUpdate);
        }
    }



    @RequestMapping(value = "join",method = RequestMethod.GET)
    public ResponseResult join(HttpServletRequest req) {



        return new ResponseResult();
    }
    @RequestMapping(value = "join",method = RequestMethod.POST)
    public ResponseResult join(HttpServletRequest req,@RequestParam(required = false) String username ) {
        int errCode = 0;
        boolean isEmail,isPhone;
        isEmail =isPhone=false;
        if(!ValidateUtils.isCaptchaValidated(req)) errCode = ResponseResult.ERR_CAPTCHA;
        else {
            isEmail = ValidateUtils.isEmail(username);
            if(!isEmail) isPhone = ValidateUtils.isPhone(username);
            if (!isEmail && !isPhone) errCode = ResponseResult.ERR_FORMAT;
            else{
                Passport passport = null;
                if (isPhone) passport = userService.getAuthenticationPassport(username, 1);
                else passport = userService.getAuthenticationPassport(username, 2);

                if(null!=passport )
                    errCode = ResponseResult.ERR_EXISTS;
            }


        }

        if(errCode==0) {
            //region 发送二次验证码
            errCode = messageService.sendRegisterCode(isPhone,username);
            //endregion

        }
        return ResponseResult.createError(errCode);
    }


    @RequestMapping(value = "joindone",method = RequestMethod.POST)
    public ResponseResult  joinDone(HttpServletRequest req,@RequestParam(required = false) String username,@RequestParam(required = false) String password,@RequestParam(required = false) String code ) {
        ResponseResult ret = null;
        String redirectUrl = null;
        int errCode = messageService.getCodeStatus(code);
        if (errCode == 0) {
            if (StringUtils.isEmpty(password) || password.length() < 6)
                ret = ResponseResult.createError(ResponseResult.ERR_BULK).put("password", ResponseResult.ERR_FORMAT);
            boolean isPhone=false;
            if (null == ret) {
                isPhone = ValidateUtils.isPhone(username);
                boolean isEmail = ValidateUtils.isEmail(username);
                if (!isPhone && !isEmail)
                    ret = ResponseResult.createError(ResponseResult.ERR_BULK).put("username", ResponseResult.ERR_FORMAT);
            }

            if (null == ret)
            {
               if (userService.createPassport(username,password,isPhone)) {
                    UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
                   try {
                       SecurityUtils.getSubject().login(usernamePasswordToken);
                   }catch (Exception ex){
                       errCode = com.chipcoo.utils.SecurityUtils.parseLoginErr(ex);
                   }

                   if(0==errCode) {
                       WxMpOAuth2AccessToken token = com.chipcoo.utils.SecurityUtils.getWxMpOAuth2AccessToken();
                       if (null != token) {
                           WxMpUser mpUser = null;
                           try {
                               mpUser = weiXinService.oauth2getUserInfo(token);
                           } catch (Exception ex) {

                           }
                           userService.bindPassport(token.getOpenId(), 3, com.chipcoo.utils.SecurityUtils.getCurrentUser().getUserID(), mpUser);

                           if (null != mpUser)
                               ret = ResponseResult.createError(errCode)
                                       .put("nickname",mpUser.getNickname())
                                       .put("headImgUrl",mpUser.getHeadImgUrl())
                                       .put("redirect",URL_APP_HOME);
                       }
                   }
                }
            }
        }

        if(null!=ret) return ret;
        else {
            if(errCode==0 && null==redirectUrl) redirectUrl= URL_APP_HOME;

            return ResponseResult.createError(errCode).redirect(redirectUrl);
        }
    }



    //用户登录控制器
    @RequestMapping(path = "login",method = RequestMethod.GET)
    public ResponseResult login(@CookieValue(value = "loginName",required = false) String loginName , HttpServletRequest req) {
        System.err.println(ContextLoader.getCurrentWebApplicationContext());
        if (!StringUtils.isEmpty(loginName)){
            return new ResponseResult().put("username",loginName);
        }
        return new ResponseResult();
    }


    @RequestMapping(path = "login",method = RequestMethod.POST)
    public Object login(HttpServletRequest req) {
        int errCode = 0;String redirectUrl=null;
        ResponseResult ret=null;
        if(!ValidateUtils.isCaptchaValidated(req)) {
            errCode = ResponseResult.ERR_CAPTCHA;
        }
        else if(null!=req.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME) ) {
            errCode = (Integer) req.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
        }else {
            WxMpOAuth2AccessToken token = com.chipcoo.utils.SecurityUtils.getWxMpOAuth2AccessToken();
            if(null!=token){

                WxMpUser mpUser = null;
                try {
                    mpUser = weiXinService.oauth2getUserInfo(token);
                }catch (Exception ex){

                }

                userService.bindPassport(token.getOpenId(),3, com.chipcoo.utils.SecurityUtils.getCurrentUser().getUserID(),mpUser);
                if(null!=mpUser)
                    ret = ResponseResult.createError(errCode)
                            .put("nickname",mpUser.getNickname())
                            .put("headImgUrl",mpUser.getHeadImgUrl())
                            .put("redirect",URL_APP_HOME);

            }
        }

        if(null!=ret) return ret;
        else {
            if(errCode==0 && null==redirectUrl) redirectUrl= URL_APP_HOME;

            return ResponseResult.createError(errCode).redirect(redirectUrl);
        }
    }


    //客户端提交CODE
    @RequestMapping(path = "loginwechatwithcode" , method = RequestMethod.GET)
    public Object loginWeChatWithCode(@RequestParam String code,@RequestParam(required = false) String state) {
        int errCode=0;
        WxMpOAuth2AccessToken token = null;
        ResponseResult ret=null;
        try {
            //验证CODE有效性
            token = weiXinService.oauth2getAccessToken(code);
        }
        catch (WxErrorException ex){
            ret = new ResponseResult(ex.getError().toString());
            ret.setCode(ResponseResult.MSG_CUSTOM);
        }
        catch (RuntimeException ex){
            errCode = ResponseResult.ERR_NET;
        }
        String redirectUrl = null;
        boolean isBind = "bind".equalsIgnoreCase(state);
        if(null!=token){
            String wxOpenId = token.getOpenId();
            Passport passportFound = userService.getAuthenticationPassport(wxOpenId, 3);
            boolean neverBind = null == passportFound;

            if(!isBind) {
                if (neverBind) {
                    if(null==com.chipcoo.utils.SecurityUtils.getCurrentUser()) {
                        com.chipcoo.utils.SecurityUtils.setWxMpOAuth2AccessToken(token);
                        redirectUrl = URL_BIND_WX;
                    }else {
                            WxMpUser mpUser = null;
                            try {
                                mpUser = weiXinService.oauth2getUserInfo(token);
                            }catch (Exception ex){}
                            userService.bindPassport(token.getOpenId(),3, com.chipcoo.utils.SecurityUtils.getCurrentUser().getUserID(),mpUser);

                            if(null!=mpUser)
                                ret= ResponseResult.createError(errCode)
                                        .put("nickname",mpUser.getNickname())
                                        .put("headImgUrl",mpUser.getHeadImgUrl())
                                        .put("redirect",URL_APP_HOME);
                    }
                }
            } else{
                //region 先登录后再 绑定
                if(null==com.chipcoo.utils.SecurityUtils.getCurrentUser()){
                    com.chipcoo.utils.SecurityUtils.setWxMpOAuth2AccessToken(token);
                    redirectUrl = URL_BIND_WX;
                }else {
                    if(neverBind){
                        WxMpUser mpUser = null;
                        try {
                            mpUser = weiXinService.oauth2getUserInfo(token);
                        }catch (Exception ex){}
                        userService.bindPassport(token.getOpenId(),3, com.chipcoo.utils.SecurityUtils.getCurrentUser().getUserID(),mpUser);
                        try {
                            redirectUrl = String.format("/register-done-wechat.html?wechat=%s", null == mpUser ? ""
                                    : URLEncoder.encode(mpUser.getNickname(), "utf-8")
                            );
                        }catch (Exception ex){}
                    }else{
                        redirectUrl = "/bind-wechat-fail.html";
                    }
                }
            }
        }else{
            //微信错误
            //redirectUrl
        }

        if(null==ret && errCode==0) {
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(token.getOpenId(),"WXToken");
            try {
                SecurityUtils.getSubject().login(usernamePasswordToken);
            }catch (Exception ex){
                errCode = com.chipcoo.utils.SecurityUtils.parseLoginErr(ex);
            }
        }

        if(null!=ret) return ret;
        else {
            if(errCode==0 && null==redirectUrl) redirectUrl= URL_APP_HOME;

            return ResponseResult.createError(errCode).redirect(redirectUrl);
        }
    }

    private static  final String URL_APP_HOME ="http://test.chipcoo.com/app";
    private static  final String URL_BIND_WX ="http://test.chipcoo.com/bind-wechat.html";


    @RequestMapping(path = "forgot", method= RequestMethod.GET )
    public ResponseResult forgot(HttpServletRequest req) {

        return new ResponseResult();
    }
    @RequestMapping(path = "forgot", method= RequestMethod.POST )
    public ResponseResult forgot(HttpServletRequest req,@RequestParam(required = false) String username ) {
        int errCode = 0;
        boolean isEmail,isPhone;
        isEmail =isPhone=false;
        if(!ValidateUtils.isCaptchaValidated(req)) errCode = ResponseResult.ERR_CAPTCHA;
        else {
            isEmail = ValidateUtils.isEmail(username);
            if (!isEmail) isPhone = ValidateUtils.isPhone(username);
            if (!isEmail && !isPhone) errCode = ResponseResult.ERR_FORMAT;
            else{
                Passport passport = null;
                if (isPhone) passport = userService.getAuthenticationPassport(username, 1);
                else passport = userService.getAuthenticationPassport(username, 2);
                if(null==passport) errCode = ResponseResult.NOT_FIND;
            }
        }

        if(errCode==0) {
            //region 发送二次验证码
            errCode = messageService.sendForgotCode(isPhone,username);
            //endregion
        }
        return ResponseResult.createError(errCode);
    }

    @RequestMapping(value = "forgotdone",method = RequestMethod.POST)
    public ResponseResult forgotDone(HttpServletRequest req,@RequestParam(required = false) String username,@RequestParam(required = false) String password,@RequestParam(required = false) String code ) {
        ResponseResult ret = null;
        int errCode = messageService.getCodeStatus(code);
        if (errCode == 0) {
            if (StringUtils.isEmpty(password) || password.length() < 6)
                ret = ResponseResult.createError(ResponseResult.ERR_BULK).put("password", ResponseResult.ERR_FORMAT);
            boolean isPhone=false;
            if (null == ret) {
                isPhone = ValidateUtils.isPhone(username);
                boolean isEmail = ValidateUtils.isEmail(username);
                if (!isPhone && !isEmail) ret = ResponseResult.createError(ResponseResult.ERR_BULK).put("username", ResponseResult.ERR_FORMAT);
            }

            if (null == ret) {
                Passport passport = null;
                if (isPhone) passport = userService.getAuthenticationPassport(username, 1);
                else passport = userService.getAuthenticationPassport(username, 2);
                if(null==passport) errCode = ResponseResult.NOT_FIND;
                else{
                    userService.changePassword(passport.getUserID(),password);
                }
            }
        }

        if (null == ret) ret = ResponseResult.createError(errCode);
        return ret;
    }

}
